/*
 * PNTreeNode.java
 *
 */

package edu.uj.petri.algorithms;

import edu.uj.petri.model.Marking;
import edu.uj.petri.model.Matrix;
import edu.uj.petri.model.Model;
import edu.uj.petri.model.Place;
import edu.uj.petri.model.Transition;
import java.util.ArrayList;
import java.util.List;

/**
* Structure repesenting node in coverability tree/graph.
 * @author mkruk
 */
public class PNTreeNode {
    private PNTreeNode parentNode = null;// reference to parent node
    private List<PNTreeNode> childNodes = new ArrayList<PNTreeNode>(); // list of references to child node(s)
    private Marking myMarking = null;
    public int[] tabMarking;
    private String label = ""; 
    private Tag tag;
    
    public enum Tag{
//        NEW("new"), OLD("old"), DEADEND("dead end");
        NEW, OLD, DEADEND, BLANK;
     }
    
    /** Creates a new instance of PNTreeNode */
    public PNTreeNode(Marking marking,String label,Tag tag) {
        this.parentNode = null;
        this.myMarking = marking;
        this.tabMarking = new int[marking.toArray().length];
        this.tabMarking = marking.toArray();
        this.label = label;
        this.tag = tag;
      
    }

    /** For internal use. Sets a reference to parent node of this node ;-)
     * @param parentNode a parent node
     * @see AddChildNode
     */
    private void setParentNode(PNTreeNode parentNode) {
        this.parentNode = parentNode;
    }
    
    /** Adds a child node
     * @param childNode node which will be add
     */
    public void AddChildNode(PNTreeNode childNode){
        (childNode).setParentNode(this);
        this.childNodes.add(childNode);
    }
    
    public void TagAsOld(){
        this.tag = Tag.OLD;
    }
    public void TagAsNew(){
        this.tag = Tag.NEW;
    }
    public void TagAsDeadEnd(){
        this.tag = Tag.DEADEND;
    }
    public void TagAsBlank(){
        this.tag = Tag.BLANK;
    }
  
    int[] GetTabMarking(){
        return this.tabMarking;
    }
    List GetChildNodes(){
        return this.childNodes;
    }
    public PNTreeNode GetParenNode(){
        return this.parentNode;
    }
    
    public String GetLabel(){
        return this.label;
    }
    
    public boolean isOmegaMarking(){
        for(int ii = 0;ii < this.tabMarking.length;++ii){
            if(this.tabMarking[ii] != -1){
                return false;
            }
        }

        return true;
        
    }
    
    /** Checikng for equal marking at paren node and sets "omega" if neeeded.
     */
    public boolean CheckMarkingAndSetOmega(){
        boolean b = false;
        

        
        if(this.parentNode != null) {
            
            int[] myMarking = getMyMarking().toArray();
            int[] ancestorMarking = parentNode.getMyMarking().toArray();
            
            boolean allGreaterOrEqual=true;
            boolean oneGreater=false;
            
            for (int i=0; i<myMarking.length; ++i) {
                if (myMarking[i] < ancestorMarking[i]) {
                    allGreaterOrEqual = false;
                    break;
                }
                if (myMarking[i] > ancestorMarking[i]) {
                    oneGreater = true;
                }
            }
            
            if (!(allGreaterOrEqual && oneGreater)) {
                return false;
            }else{
            
                int[] mParent = (this.parentNode.GetTabMarking());
                for(int ii = 0;ii < mParent.length;++ii){

//                if((this.tabMarking[ii] > mParent[ii]) || (mParent[ii] == -1)){
                    if((this.tabMarking[ii] > mParent[ii])){
                        this.tabMarking[ii] = -1;
                        b = true;
                    }
                }
            }
        }
        
        return b;

    }
    /** For internal use. Recursivly compares marking up to parent node.
     * @param node the node which marking is compare.
     * @see HasEqualMarking
     */
    private boolean CompareMarking(PNTreeNode node){
        if(node != null) { // if(this.parentNode != null){

            /*if(node.getMyMarking().equals(this.getMyMarking())){
                return true;
            }
        
            if((this.parentNode).CompareMarking(node)){
                return true;
            }
            */
//            int[] thisMarking = myMarking.toArray();
//            int[] ancestorMarking = node.myMarking.toArray();
            int[] thisMarking = this.tabMarking;
            int[] ancestorMarking = node.tabMarking;
            
            boolean equal=true;
            for (int i=0; i<thisMarking.length; ++i) {
                if (thisMarking[i] != ancestorMarking[i]) {
                    equal = false;
                    break;
                }
            }
            
            if (equal) {
                return true;
            } else {
                return CompareMarking(node.parentNode);
            }
        }

        return false;

    }    
   /** Returns true if equal marking for current node occur.
     * @see #HasEqualMarking()
     */    
    public boolean HasEqualMarking(){
        return CompareMarking(parentNode); // was: this
    }
    
    public boolean isCovered() {
        return checkCover(parentNode);
    }
    
    private boolean checkCover(PNTreeNode node) {
        if (node != null) {
            int[] myMarking = getMyMarking().toArray();
            int[] ancestorMarking = node.getMyMarking().toArray();
            
            boolean allGreaterOrEqual=true;
            boolean oneGreater=false;
            
            for (int i=0; i<myMarking.length; ++i) {
                if (myMarking[i] < ancestorMarking[i]) {
                    allGreaterOrEqual = false;
                    break;
                }
                if (myMarking[i] > ancestorMarking[i]) {
                    oneGreater = true;
                }
            }
            
            if (allGreaterOrEqual && oneGreater) {
                return true;
            }
            
            return checkCover(node.GetParenNode());
        }
        
        return false;
    }
    
    

    public Marking getMyMarking() {
        return myMarking;
    }
    
    public Tag GetTag(){
        return this.tag;
    }
    
    public void SetTag(Tag t){
        this.tag = t;
    }
    
    public String toString(){
        String ss = "<html>";
        ss += this.label + "<b> [ ";
//        ss += "<font color=red>" + this.label + "</font> [ ";
        for(int ii = 0;ii < this.tabMarking.length;++ii){
            int iTmp = tabMarking[ii];
            if(iTmp < 0){ // unbounded number of tokens
                ss += "w ";
            }else{
                ss += iTmp + " ";
            }
        }
        
        ss += "] </b>";
        if(this.tag != Tag.BLANK){
//            ss += "<font color=blue>" + this.tag.toString() + "</font>";
            ss += this.tag.toString();
        }
        
        ss += "</html>";
        return ss;
    }    
    
   
    
}
